home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / utils / cache / catcache.c next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  27.5 KB  |  1,045 lines

  1. /* ----------------------------------------------------------------
  2.  * catcache.c --
  3.  *    System catalog cache for tuples matching a key.
  4.  *
  5.  * Notes:
  6.  *    XXX This needs to use exception.h to handle recovery when
  7.  *        an abort occurs during DisableCache.
  8.  *    
  9.  * ----------------------------------------------------------------
  10.  */
  11. #include "tmp/postgres.h"
  12.  
  13. RcsId("$Header: /private/postgres/src/utils/cache/RCS/catcache.c,v 1.32 1992/04/03 01:07:17 mer Exp $");
  14.  
  15. #include "access/heapam.h"
  16. #include "access/genam.h"
  17. #include "access/tqual.h"
  18. #include "storage/bufpage.h"
  19. #include "access/valid.h"
  20. #include "tmp/miscadmin.h"
  21. #include "tmp/portal.h"
  22. #include "utils/catcache.h"
  23. #include "utils/fmgr.h"        /* for F_BOOLEQ, etc.  DANGER */
  24. #include "utils/log.h"
  25. #include "utils/mcxt.h"
  26. #include "utils/rel.h"
  27. #include "catalog/pg_type.h"    /* for OID of int28 type */
  28.  
  29. /* ----------------
  30.  *    variables, macros and other stuff
  31.  *
  32.  *  note CCSIZE allocates 51 buckets .. one was already allocated in
  33.  *  the catcache structure.
  34.  * ----------------
  35.  */
  36.  
  37. #ifdef CACHEDEBUG
  38. #define CACHE1_elog(a,b)        elog(a,b)
  39. #define CACHE2_elog(a,b,c)        elog(a,b,c)
  40. #define CACHE3_elog(a,b,c,d)        elog(a,b,c,d)
  41. #define CACHE4_elog(a,b,c,d,e)        elog(a,b,c,d,e)
  42. #define CACHE5_elog(a,b,c,d,e,f)    elog(a,b,c,d,e,f)
  43. #define CACHE6_elog(a,b,c,d,e,f,g)    elog(a,b,c,d,e,f,g)
  44. #else
  45. #define CACHE1_elog(a,b)
  46. #define CACHE2_elog(a,b,c)
  47. #define CACHE3_elog(a,b,c,d)
  48. #define CACHE4_elog(a,b,c,d,e)
  49. #define CACHE5_elog(a,b,c,d,e,f)
  50. #define CACHE6_elog(a,b,c,d,e,f,g)
  51. #endif
  52.  
  53. #define    NCCBUCK    50    /* CatCache buckets             */
  54. #define MAXTUP 30    /* Maximum # of tuples cached per cache */
  55. #define LIST    SLList
  56. #define NODE    SLNode
  57. #define CCSIZE    (sizeof(struct catcache) + NCCBUCK * sizeof(SLList))
  58.  
  59. struct catcache    *Caches = NULL;
  60. GlobalMemory    CacheCxt;
  61. static int    DisableCache;
  62.  
  63. /* ----------------
  64.  *    EQPROC is used in CatalogCacheInitializeCache
  65.  *     XXX this should be replaced by catalog lookups soon
  66.  * ----------------
  67.  */
  68. static long    eqproc[] = {
  69.     F_BOOLEQ, 0l, F_CHAREQ, F_CHAR16EQ, 0l,
  70.     F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, 0l, F_TEXTEQ,
  71.     F_OIDEQ, 0l, 0l, 0l, 0l
  72. };
  73.  
  74. #define    EQPROC(SYSTEMTYPEOID)    eqproc[(SYSTEMTYPEOID)-16]
  75.     ;
  76.  
  77. /* ----------------------------------------------------------------
  78.  *            internal support functions
  79.  * ----------------------------------------------------------------
  80.  */
  81. /* --------------------------------
  82.  *    CatalogCacheInitializeCache
  83.  * --------------------------------
  84.  */
  85. #ifdef CACHEDEBUG
  86. #define CatalogCacheInitializeCache_DEBUG1 \
  87.     elog(DEBUG, "CatalogCacheInitializeCache: cache @%08lx", cache); \
  88.     if (relation) \
  89.         elog(DEBUG, "CatalogCacheInitializeCache: called w/relation(inval)"); \
  90.     else \
  91.         elog(DEBUG, "CatalogCacheInitializeCache: called w/relname %s", \
  92.         cache->cc_relname)
  93. #define CatalogCacheInitializeCache_DEBUG2 \
  94.         if (cache->cc_key[i] > 0) { \
  95.             elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d, %d", \
  96.             i+1, cache->cc_nkeys, cache->cc_key[i], \
  97.             relation->rd_att.data[cache->cc_key[i] - 1]->attlen); \
  98.     } else { \
  99.             elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d", \
  100.             i+1, cache->cc_nkeys, cache->cc_key[i]); \
  101.     }
  102. #else
  103. #define CatalogCacheInitializeCache_DEBUG1
  104. #define CatalogCacheInitializeCache_DEBUG2
  105. #endif
  106.  
  107. /**** xxref:
  108.  *           CatalogCacheComputeTupleHashIndex
  109.  *           SearchSysCache
  110.  ****/
  111. void
  112. CatalogCacheInitializeCache(cache, relation)
  113.     struct catcache *cache;
  114.     Relation relation;
  115. {
  116.     MemoryContext    oldcxt;
  117.     short         didopen = 0;
  118.     short         i;
  119.     TupleDescriptor    tupdesc;
  120.     
  121.     CatalogCacheInitializeCache_DEBUG1;
  122.     
  123.     /* ----------------
  124.      *    first switch to the cache context so our allocations
  125.      *  do not vanish at the end of a transaction
  126.      * ----------------
  127.      */
  128.     if (!CacheCxt)
  129.        CacheCxt = CreateGlobalMemory("Cache");
  130.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  131.     
  132.     /* ----------------
  133.      *  If no relation was passed we must open it to get access to 
  134.      *  its fields.  If one of the other caches has already opened
  135.      *  it we use heap_open() instead of heap_openr()
  136.      * ----------------
  137.      */
  138.     if (! RelationIsValid(relation)) {
  139.     struct catcache *cp;
  140.     /* ----------------
  141.      *  scan the caches to see if any other cache has opened the relation
  142.      * ----------------
  143.      */
  144.         for (cp = Caches; cp; cp = cp->cc_next) {
  145.         if (strcmp(cp->cc_relname, cache->cc_relname) == 0) {
  146.         if (cp->relationId != InvalidObjectId)
  147.             break;
  148.         }
  149.     }
  150.     
  151.     /* ----------------
  152.      *  open the relation by name or by id
  153.      * ----------------
  154.      */
  155.     if (cp)
  156.             relation = heap_open(cp->relationId);
  157.     else
  158.             relation = heap_openr(cache->cc_relname);
  159.     
  160.     didopen = 1;
  161.     }
  162.     
  163.     /* ----------------
  164.      *    initialize the cache's relation id
  165.      * ----------------
  166.      */
  167.     Assert(RelationIsValid(relation));
  168.     cache->relationId = RelationGetRelationId(relation);
  169.     tupdesc = cache->cc_tupdesc = RelationGetTupleDescriptor(relation);
  170.     
  171.     CACHE3_elog(DEBUG, "CatalogCacheInitializeCache: relid %d, %d keys", 
  172.         cache->relationId, cache->cc_nkeys);
  173.     
  174.     /* ----------------
  175.      *    initialize cache's key information
  176.      * ----------------
  177.      */
  178.     for (i = 0; i < cache->cc_nkeys; ++i) {
  179.     CatalogCacheInitializeCache_DEBUG2;
  180.     
  181.     if (cache->cc_key[i] > 0) {
  182.  
  183.         /*
  184.          *  Yoiks.  The implementation of the hashing code and the
  185.          *  implementation of int28's are at loggerheads.  The right
  186.          *  thing to do is to throw out the implementation of int28's
  187.          *  altogether; until that happens, we do the right thing here
  188.          *  to guarantee that the hash key generator doesn't try to
  189.          *  dereference an int2 by mistake.
  190.          */
  191.  
  192.         if (tupdesc->data[cache->cc_key[i]-1]->atttypid == INT28OID)
  193.         cache->cc_klen[i] = sizeof (short);
  194.         else
  195.         cache->cc_klen[i] = tupdesc->data[cache->cc_key[i]-1]->attlen;
  196.  
  197.         cache->cc_skey[i].sk_opr =
  198.             EQPROC(tupdesc->data[cache->cc_key[i]-1]->atttypid);
  199.  
  200.         fmgr_info(cache->cc_skey[i].sk_opr, 
  201.                   &cache->cc_skey[i].func,
  202.                   &cache->cc_skey[i].nargs);
  203.  
  204.         CACHE5_elog(DEBUG, "CatalogCacheInit %16s %d %d %x",
  205.             &relation->rd_rel->relname,
  206.             i,
  207.             tupdesc->data[ cache->cc_key[i]-1 ]->attlen,
  208.             cache);
  209.     }
  210.     }
  211.  
  212.     /* ----------------
  213.      *    close the relation if we opened it
  214.      * ----------------
  215.      */
  216.     if (didopen)
  217.         heap_close(relation);
  218.  
  219.     /* ----------------
  220.      *    initialize index information for the cache.  this
  221.      *  should only be done once per cache.
  222.      * ----------------
  223.      */
  224.     if (cache->cc_indname != NULL && cache->indexId == InvalidObjectId)
  225.     {
  226.     if (RelationGetRelationTupleForm(relation)->relhasindex)
  227.     {
  228.         NameData nd;
  229.  
  230.         strncpy(&nd.data[0], cache->cc_indname, 16);
  231.         /*
  232.          * If the index doesn't exist we are in trouble.
  233.          */
  234.         relation = (Relation) index_openr(&nd);
  235.         Assert(relation);
  236.         cache->indexId = RelationGetRelationId(relation);
  237.         index_close(relation);
  238.         }
  239.     else
  240.         cache->cc_indname = NULL;
  241.     }
  242.     
  243.     /* ----------------
  244.      *    return to the proper memory context
  245.      * ----------------
  246.      */
  247.     MemoryContextSwitchTo(oldcxt);
  248. }
  249.   
  250. /* --------------------------------
  251.  *    CatalogCacheSetId
  252.  *
  253.  *     XXX temporary function
  254.  * --------------------------------
  255.  */
  256. /**** xxref:
  257.  *           InitCatalogCache
  258.  *           SearchSysCacheTuple
  259.  ****/
  260. void
  261. CatalogCacheSetId(cacheInOutP, id)
  262.     CatCache *cacheInOutP;
  263.     int      id;
  264. {
  265.     Assert(id == InvalidCatalogCacheId || id >= 0);
  266.     cacheInOutP->id = id;
  267. }
  268.  
  269. /* ----------------
  270.  * comphash --
  271.  *    Compute a hash value, somehow.
  272.  *
  273.  * XXX explain algorithm here.
  274.  *
  275.  * l is length of the attribute value, v
  276.  * v is the attribute value ("Datum")
  277.  * ----------------
  278.  */
  279. /**** xxref:
  280.  *           CatalogCacheComputeHashIndex
  281.  ****/
  282. comphash(l, v)
  283.     int            l;
  284.     register char    *v;
  285. {
  286.     register int  i;
  287.     CACHE3_elog(DEBUG, "comphash (%d,%x)", l, v);
  288.     
  289.     switch (l) {
  290.     case 1:
  291.     case 2:
  292.     case 4:
  293.     return((int) v);
  294.     }
  295.  
  296.     /* special hack for char16 values */
  297.     if (l == 16)
  298.     l = NameComputeLength((Name)v);
  299.     else if (l < 0)
  300.     l = VARSIZE(v);
  301.  
  302.     i = 0;
  303.     while (l--) {
  304.     i += *v++;
  305.     }
  306.     return(i);
  307. }
  308. /* --------------------------------
  309.  *    CatalogCacheComputeHashIndex
  310.  * --------------------------------
  311.  */
  312.  
  313. /**** xxref:
  314.  *           CatalogCacheComputeTupleHashIndex
  315.  *           SearchSysCache
  316.  ****/
  317. Index
  318. CatalogCacheComputeHashIndex(cacheInP)
  319.     struct catcache *cacheInP;
  320. {
  321.     Index    hashIndex;
  322.     hashIndex = 0x0;
  323.     CACHE6_elog(DEBUG,"CatalogCacheComputeHashIndex %s %d %d %d %x",
  324.      cacheInP->cc_relname,
  325.      cacheInP->cc_nkeys,
  326.      cacheInP->cc_klen[0],
  327.      cacheInP->cc_klen[1],
  328.      cacheInP);
  329.     
  330.     switch (cacheInP->cc_nkeys) {
  331.     case 4:
  332.     hashIndex ^= comphash(cacheInP->cc_klen[3],
  333.         cacheInP->cc_skey[3].sk_data) << 9;
  334.     /* FALLTHROUGH */
  335.     case 3:
  336.     hashIndex ^= comphash(cacheInP->cc_klen[2],
  337.         cacheInP->cc_skey[2].sk_data) << 6;
  338.     /* FALLTHROUGH */
  339.     case 2:
  340.     hashIndex ^= comphash(cacheInP->cc_klen[1],
  341.         cacheInP->cc_skey[1].sk_data) << 3;
  342.     /* FALLTHROUGH */
  343.     case 1:
  344.     hashIndex ^= comphash(cacheInP->cc_klen[0],
  345.         cacheInP->cc_skey[0].sk_data);
  346.     break;
  347.     default:
  348.     elog(FATAL, "CCComputeHashIndex: %d cc_nkeys", cacheInP->cc_nkeys);
  349.     break;
  350.     }
  351.     hashIndex %= cacheInP->cc_size;
  352.     return (hashIndex);
  353. }
  354.  
  355. /* --------------------------------
  356.  *    CatalogCacheComputeTupleHashIndex
  357.  * --------------------------------
  358.  */
  359. /**** xxref:
  360.  *           RelationInvalidateCatalogCacheTuple
  361.  ****/
  362. Index
  363. CatalogCacheComputeTupleHashIndex(cacheInOutP, relation, tuple)
  364.     struct catcache    *cacheInOutP;
  365.     Relation        relation;
  366.     HeapTuple        tuple;
  367. {
  368.     Boolean        isNull = '\0';
  369.     extern DATUM    fastgetattr();
  370.     if (cacheInOutP->relationId == InvalidObjectId)
  371.     CatalogCacheInitializeCache(cacheInOutP, relation);
  372.     switch (cacheInOutP->cc_nkeys) {
  373.     case 4:
  374.     cacheInOutP->cc_skey[3].sk_data =
  375.         (cacheInOutP->cc_key[3] == ObjectIdAttributeNumber)
  376.         ? (DATUM) tuple->t_oid
  377.         : fastgetattr(tuple,
  378.                   cacheInOutP->cc_key[3],
  379.                   &relation->rd_att.data[0],
  380.                   &isNull);
  381.     Assert(!isNull);
  382.     /* FALLTHROUGH */
  383.     case 3:
  384.     cacheInOutP->cc_skey[2].sk_data =
  385.         (cacheInOutP->cc_key[2] == ObjectIdAttributeNumber)
  386.         ? (DATUM) tuple->t_oid
  387.         : fastgetattr(tuple,
  388.                   cacheInOutP->cc_key[2],
  389.                   &relation->rd_att.data[0],
  390.                   &isNull);
  391.     Assert(!isNull);
  392.     /* FALLTHROUGH */
  393.     case 2:
  394.     cacheInOutP->cc_skey[1].sk_data =
  395.         (cacheInOutP->cc_key[1] == ObjectIdAttributeNumber)
  396.         ? (DATUM) tuple->t_oid
  397.         : fastgetattr(tuple,
  398.                   cacheInOutP->cc_key[1],
  399.                   &relation->rd_att.data[0],
  400.                   &isNull);
  401.     Assert(!isNull);
  402.     /* FALLTHROUGH */
  403.     case 1:
  404.     cacheInOutP->cc_skey[0].sk_data =
  405.         (cacheInOutP->cc_key[0] == ObjectIdAttributeNumber)
  406.         ? (DATUM) tuple->t_oid
  407.         : fastgetattr(tuple,
  408.                   cacheInOutP->cc_key[0],
  409.                   &relation->rd_att.data[0],
  410.                   &isNull);
  411.     Assert(!isNull);
  412.     break;
  413.     default:
  414.     elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys",
  415.         cacheInOutP->cc_nkeys
  416.     );
  417.     break;
  418.     }
  419.     
  420.     return
  421.     CatalogCacheComputeHashIndex(cacheInOutP);
  422. }
  423.  
  424. /* --------------------------------
  425.  *    CatCacheRemoveCTup
  426.  * --------------------------------
  427.  */
  428.  
  429. /**** xxref:
  430.  *           CatalogCacheIdInvalidate
  431.  *           ResetSystemCache
  432.  *           SearchSysCache
  433.  ****/
  434. void
  435. CatCacheRemoveCTup(cache, ct)
  436.     CatCache *cache;
  437.     CatCTup  *ct;
  438. {
  439.     SLRemove(&ct->ct_node);
  440.     SLRemove(&ct->ct_lrunode);
  441.     HeapTupleFreeRuleLock(ct->ct_tup);    /* XXX: careful here... */
  442.     pfree((char *) ct->ct_tup);
  443.     pfree((char *)ct);
  444.     --cache->cc_ntup;
  445. }
  446.  
  447. /* --------------------------------
  448.  *  CatalogCacheIdInvalidate()
  449.  *
  450.  *  Invalidate a tuple given a cache id.  In this case the id should always
  451.  *  be found (whether the cache has opened its relation or not).  Of course,
  452.  *  if the cache has yet to open its relation, there will be no tuples so
  453.  *  no problem.
  454.  * --------------------------------
  455.  */
  456. /**** xxref:
  457.  *           CacheIdInvalidate
  458.  *           InvalidationMessageCacheInvalidate
  459.  ****/
  460. void
  461. CatalogCacheIdInvalidate(cacheId, hashIndex, pointer)
  462.     int        cacheId;    /* XXX */
  463.     Index    hashIndex;
  464.     ItemPointer    pointer;
  465. {
  466.     struct catcache     *ccp;
  467.     struct catctup    *ct, *hct;
  468.     MemoryContext    oldcxt;
  469.     
  470.     /* ----------------
  471.      *    sanity checks
  472.      * ----------------
  473.      */
  474.     Assert(IndexIsValid(hashIndex) && IndexIsInBounds(hashIndex, NCCBUCK));
  475.     Assert(ItemPointerIsValid(pointer));
  476.     CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
  477.     
  478.     /* ----------------
  479.      *    switch to the cache context for our memory allocations
  480.      * ----------------
  481.      */
  482.     if (!CacheCxt)
  483.        CacheCxt = CreateGlobalMemory("Cache");
  484.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  485.     
  486.     /* ----------------
  487.      *    inspect every cache that could contain the tuple
  488.      * ----------------
  489.      */
  490.     for (ccp = Caches; ccp; ccp = ccp->cc_next) {
  491.     if (cacheId != ccp->id) 
  492.             continue;
  493.     /* ----------------
  494.      *  inspect the hash bucket until we find a match or exhaust
  495.      * ----------------
  496.      */
  497.     for (ct = (CatCTup *) SLGetHead(&ccp->cc_cache[hashIndex]);
  498.          ct;
  499.          ct = (CatCTup *) SLGetSucc(&ct->ct_node))
  500.     {
  501.         if (ItemPointerEquals(pointer, &ct->ct_tup->t_ctid)) 
  502.         break;
  503.      }
  504.     
  505.     /* ----------------
  506.      *  if we found a matching tuple, invalidate it.
  507.      * ----------------
  508.      */
  509.     if (ct) {
  510.         CatCacheRemoveCTup(ccp, ct);
  511.         
  512.         CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");
  513.     }
  514.     
  515.     if (cacheId != InvalidCatalogCacheId) 
  516.         break;
  517.     }
  518.     
  519.     /* ----------------
  520.      *    return to the proper memory context
  521.      * ----------------
  522.      */
  523.     MemoryContextSwitchTo(oldcxt);
  524.     /*    sendpm('I', "Invalidated tuple"); */
  525. }
  526.  
  527. /* ----------------------------------------------------------------
  528.  *               public functions
  529.  *
  530.  *    ResetSystemCache
  531.  *    InitIndexedSysCache
  532.  *    InitSysCache
  533.  *      SearchSysCache
  534.  *      RelationInvalidateCatalogCacheTuple
  535.  * ----------------------------------------------------------------
  536.  */
  537. /* --------------------------------
  538.  *    ResetSystemCache
  539.  * --------------------------------
  540.  */
  541. /**** xxref:
  542.  *           ResetSystemCaches
  543.  ****/
  544.  
  545. void
  546. ResetSystemCache()
  547. {
  548.     MemoryContext    oldcxt;
  549.     struct catcache    *cache;
  550.     
  551.     /* ----------------
  552.      *    sanity checks
  553.      * ----------------
  554.      */
  555.     CACHE1_elog(DEBUG, "ResetSystemCache called");
  556.     if (DisableCache) {
  557.     elog(WARN, "ResetSystemCache: Called while cache disabled");
  558.     return;
  559.     }
  560.     
  561.     /* ----------------
  562.      *    first switch to the cache context so our allocations
  563.      *  do not vanish at the end of a transaction
  564.      * ----------------
  565.      */
  566.     if (!CacheCxt)
  567.        CacheCxt = CreateGlobalMemory("Cache");
  568.     
  569.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  570.     
  571.     /* ----------------
  572.      *  here we purge the contents of all the caches
  573.      *
  574.      *    for each system cache
  575.      *     for each hash bucket
  576.      *         for each tuple in hash bucket
  577.      *           remove the tuple
  578.      * ----------------
  579.      */
  580.     for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next) {
  581.         register int hash;
  582.     for (hash = 0; hash < NCCBUCK; hash += 1) {
  583.         LIST *list = &cache->cc_cache[hash];
  584.         register CatCTup *ct, *nextct;
  585.         for (ct = (CatCTup *) SLGetHead(list); ct; ct = nextct) {
  586.         nextct = (CatCTup *)SLGetSucc(&ct->ct_node);
  587.         CatCacheRemoveCTup(cache, ct);
  588.         
  589.             if (cache->cc_ntup == -1) 
  590.             elog(WARN, "ResetSystemCache: cc_ntup<0 (software error)");
  591.         }
  592.     }
  593.     cache->cc_ntup = 0; /* in case of WARN error above */
  594.     }
  595.     
  596.     CACHE1_elog(DEBUG, "end of ResetSystemCache call");
  597.     
  598.     /* ----------------
  599.      *    back to the old context before we return...
  600.      * ----------------
  601.      */
  602.     MemoryContextSwitchTo(oldcxt);
  603. }
  604.  
  605. /* --------------------------------
  606.  *    InitIndexedSysCache
  607.  *
  608.  *  This allocates and initializes a cache for a system catalog relation.
  609.  *  Actually, the cache is only partially initialized to avoid opening the
  610.  *  relation.  The relation will be opened and the rest of the cache
  611.  *  structure initialized on the first access.
  612.  * --------------------------------
  613.  */
  614. #ifdef CACHEDEBUG
  615. #define InitSysCache_DEBUG1 \
  616.     elog(DEBUG, "InitSysCache: rid=%d id=%d nkeys=%d size=%d\n", \
  617.      cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); \
  618.     for (i = 0; i < nkeys; i += 1) { \
  619.         elog(DEBUG, "InitSysCache: key=%d len=%d skey=[%d %d %d %d]\n", \
  620.             cp->cc_key[i], cp->cc_klen[i], \
  621.             cp->cc_skey[i].sk_flags, \
  622.             cp->cc_skey[i].sk_attnum, \
  623.             cp->cc_skey[i].sk_opr, \
  624.             cp->cc_skey[i].sk_data); \
  625.     }
  626. #else
  627. #define InitSysCache_DEBUG1
  628. #endif
  629.     
  630. /**** xxref:
  631.  *           InitCatalogCache
  632.  *           SearchSysCacheTuple
  633.  ****/
  634. struct catcache *
  635. InitIndexedSysCache(relname, indname, nkeys, key, iScanfuncP)
  636.     char    *relname;
  637.     char    *indname;
  638.     int        nkeys;
  639.     int        key[];
  640.     HeapTuple   (*iScanfuncP)();
  641. {
  642.     struct catcache     *cp;
  643.     register int        i;
  644.     MemoryContext    oldcxt;
  645.     
  646.     /* ----------------
  647.      *    first switch to the cache context so our allocations
  648.      *  do not vanish at the end of a transaction
  649.      * ----------------
  650.      */
  651.     if (!CacheCxt)
  652.        CacheCxt = CreateGlobalMemory("Cache");
  653.     
  654.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  655.     
  656.     /* ----------------
  657.      *  allocate a new cache structure
  658.      * ----------------
  659.      */
  660.     cp = (struct catcache *) palloc(CCSIZE);
  661.     bzero((char *)cp, CCSIZE);
  662.     
  663.     /* ----------------
  664.      *    initialize the cache buckets (each bucket is a list header)
  665.      *  and the LRU tuple list
  666.      * ----------------
  667.      */
  668.     for (i = 0; i <= NCCBUCK; ++i)
  669.     SLNewList(&cp->cc_cache[i], offsetof(struct catctup, ct_node));
  670.     
  671.     SLNewList(&cp->cc_lrulist, offsetof(struct catctup, ct_lrunode));
  672.     
  673.     /* ----------------
  674.      *  Caches is the pointer to the head of the list of all the
  675.      *  system caches.  here we add the new cache to the top of the list.
  676.      * ----------------
  677.      */
  678.     cp->cc_next = Caches;  /* list of caches (single link) */
  679.     Caches = cp;
  680.     
  681.     /* ----------------
  682.      *    initialize the cache's relation information for the relation
  683.      *  corresponding to this cache and initialize some of the the new
  684.      *  cache's other internal fields.
  685.      * ----------------
  686.      */
  687.     cp->relationId =     InvalidObjectId;
  688.     cp->indexId =     InvalidObjectId;
  689.     cp->cc_relname =     relname;
  690.     cp->cc_indname =     indname;
  691.     cp->cc_tupdesc =    (TupleDescriptor) NULL;
  692.     cp->id =         InvalidCatalogCacheId;    /* XXX should be an argument */
  693.     cp->cc_maxtup =     MAXTUP;
  694.     cp->cc_size =     NCCBUCK;
  695.     cp->cc_nkeys =     nkeys;
  696.     cp->cc_iscanfunc =     iScanfuncP;
  697.     
  698.     /* ----------------
  699.      *    initialize the cache's key information
  700.      * ----------------
  701.      */
  702.     for (i = 0; i < nkeys; ++i) {
  703.     cp->cc_key[i] = key[i];
  704.     if (!key[i]) {
  705.         elog(FATAL, "InitSysCache: called with 0 key[%d]", i);
  706.     }
  707.     if (key[i] < 0) {
  708.         if (key[i] != ObjectIdAttributeNumber) {
  709.         elog(FATAL, "InitSysCache: called with %d key[%d]", key[i], i);
  710.         } else {
  711.         cp->cc_klen[i] = sizeof(OID);
  712.         /*
  713.          * ScanKeyEntryData and struct skey are equivalent. It looks
  714.          * like a move was made to obsolete struct skey, but it
  715.          * didn't reach this file.  Someday we should clean up this
  716.          * code and consolidate to ScanKeyEntry - mer 10 Nov 1991
  717.          */
  718.         ScanKeyEntryInitialize((ScanKeyEntry)&cp->cc_skey[i], 
  719.                        (bits16)0,
  720.                        (AttributeNumber)key[i],
  721.                        (RegProcedure)F_OIDEQ,
  722.                        (Datum)0);
  723.         continue;
  724.         }
  725.     }
  726.     
  727.     cp->cc_skey[i].sk_attnum = key[i];
  728.     }
  729.  
  730.     /* ----------------
  731.      *    all done.  new cache is initialized.  print some debugging
  732.      *  information, if appropriate.
  733.      * ----------------
  734.      */
  735.     InitSysCache_DEBUG1;
  736.     
  737.     /* ----------------
  738.      *    back to the old context before we return...
  739.      * ----------------
  740.      */
  741.     MemoryContextSwitchTo(oldcxt);
  742.     return(cp);
  743. }
  744.  
  745. struct catcache *
  746. InitSysCache(relname, indname, nkeys, key, iScanfuncP)
  747.     char    *relname;
  748.     Name    *indname;
  749.     int        nkeys;
  750.     int        key[];
  751.     HeapTuple   (*iScanfuncP)();
  752. {
  753.     char *iname;
  754.  
  755.     /*
  756.      * Doing the POSTGRES name dance.
  757.      */
  758.     iname = (indname) ? &((*indname)->data[0]) : NULL;
  759.  
  760.     return InitIndexedSysCache(relname, iname, nkeys, key, iScanfuncP);
  761. }
  762.  
  763.  
  764. /* --------------------------------
  765.  *      SearchSysCache
  766.  *
  767.  *      This call searches a system cache for a tuple, opening the relation
  768.  *      if necessary (the first access to a particular cache).
  769.  * --------------------------------
  770.  */
  771. /**** xxref:
  772.  *           SearchSysCacheTuple
  773.  ****/
  774. HeapTuple
  775. SearchSysCache(cache, v1, v2, v3, v4)
  776.     register struct catcache    *cache;
  777.     DATUM            v1, v2, v3, v4;
  778. {
  779.     register unsigned    hash;
  780.     register CatCTup    *ct;
  781.     HeapTuple        ntp;
  782.     Buffer        buffer;
  783.     struct catctup    *nct;
  784.     Relation        relation;
  785.     MemoryContext    oldcxt;
  786.     
  787.     /* ----------------
  788.      *    sanity checks
  789.      * ----------------
  790.      */
  791.     if (cache->relationId == InvalidObjectId)
  792.     CatalogCacheInitializeCache(cache, NULL);
  793.     
  794.     if (DisableCache) {
  795.     elog(WARN, "SearchSysCache: Called while cache disabled");
  796.     return((HeapTuple) NULL);
  797.     }
  798.  
  799.     /* ----------------
  800.      *    initialize the search key information
  801.      * ----------------
  802.      */
  803.     cache->cc_skey[0].sk_data = v1;
  804.     cache->cc_skey[1].sk_data = v2;
  805.     cache->cc_skey[2].sk_data = v3;
  806.     cache->cc_skey[3].sk_data = v4;
  807.     
  808.     /* ----------------
  809.      *    find the hash bucket in which to look for the tuple
  810.      * ----------------
  811.      */
  812.     hash = CatalogCacheComputeHashIndex(cache);
  813.     
  814.     /* ----------------
  815.      *    scan the hash bucket until we find a match or exhaust our tuples
  816.      * ----------------
  817.      */
  818.     for (ct = (CatCTup *)SLGetHead(&cache->cc_cache[hash]); 
  819.      ct;
  820.      ct = (CatCTup *)SLGetSucc(&ct->ct_node))
  821.     {
  822.     /* ----------------
  823.      *  see if the cached tuple matches our key.
  824.      *  (should we be worried about time ranges? -cim 10/2/90)
  825.      * ----------------
  826.      */
  827.     if (keytest_tupdesc(ct->ct_tup,
  828.                 cache->cc_tupdesc,
  829.                 cache->cc_nkeys,
  830.                 cache->cc_skey))
  831.         break;
  832.     }
  833.     
  834.     /* ----------------
  835.      *    if we found a tuple in the cache, move it to the top of the
  836.      *  lru list, and return it.
  837.      * ----------------
  838.      */
  839.     if (ct) {
  840.     SLRemove(&ct->ct_lrunode);        /* most recently used */
  841.     SLAddHead(&cache->cc_lrulist, &ct->ct_lrunode);
  842.     
  843. #ifdef CACHEDEBUG
  844.     relation = heap_open(cache->relationId);
  845.     CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",
  846.             RelationGetRelationName(relation), hash);
  847.     heap_close(relation);
  848. #endif CACHEDEBUG
  849.     
  850.     return
  851.         (ct->ct_tup);
  852.     }
  853.     
  854.     /* ----------------
  855.      *    Tuple was not found in cache, so we have to try and
  856.      *  retrieve it directly from the relation.  If it's found,
  857.      *  we add it to the cache.
  858.      * ----------------
  859.      */
  860.     /* ----------------
  861.      *    open the relation associated with the cache
  862.      * ----------------
  863.      */
  864.     relation = heap_open(cache->relationId);
  865.     CACHE2_elog(DEBUG, "SearchSysCache(%s)",
  866.         RelationGetRelationName(relation));
  867.  
  868.     /* ----------------
  869.      *  DisableCache and then switch to the cache memory context.
  870.      * ----------------
  871.      */
  872.     DisableCache = 1;
  873.         
  874.     if (!CacheCxt)
  875.        CacheCxt = CreateGlobalMemory("Cache");
  876.     
  877.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  878.    
  879.     /* ----------------
  880.      *    now preform a scan of the relation
  881.      *  ADD INDEXING HERE.
  882.      * ----------------
  883.      */
  884.     CACHE2_elog(DEBUG, "SearchSysCache: performing scan (override==%d)",
  885.         heapisoverride());
  886.     
  887.     if ((RelationGetRelationTupleForm(relation))->relhasindex)
  888.     {
  889.     Assert(cache->cc_iscanfunc);
  890.     switch(cache->cc_nkeys)
  891.     {
  892.         case 4: ntp = cache->cc_iscanfunc(relation,v1,v2,v3,v4); break;
  893.         case 3: ntp = cache->cc_iscanfunc(relation,v1,v2,v3); break;
  894.         case 2: ntp = cache->cc_iscanfunc(relation,v1,v2); break;
  895.         case 1: ntp = cache->cc_iscanfunc(relation,v1); break;
  896.     }
  897.     }
  898.     else
  899.     {
  900.     HeapScanDesc    sd;
  901.  
  902.     sd =  heap_beginscan(relation, 0, NowTimeQual,
  903.                  cache->cc_nkeys, cache->cc_skey);
  904.     
  905.     ntp = heap_getnext(sd, 0, &buffer);
  906.     
  907.     if (HeapTupleIsValid(ntp)) {
  908.         CACHE1_elog(DEBUG, "SearchSysCache: found tuple");
  909.         ntp = palloctup(ntp, buffer, relation);
  910.     }
  911.  
  912.     heap_endscan(sd);
  913.     }
  914.        
  915.     DisableCache = 0;
  916.     
  917.     /* ----------------
  918.      *    scan is complete.  if tup is valid, we copy it and add the copy to
  919.      *  the cache.
  920.      * ----------------
  921.      */
  922.     if (HeapTupleIsValid(ntp)) {
  923.     /* ----------------
  924.      *  allocate a new cache tuple holder, store the pointer
  925.      *  to the heap tuple there and initialize the list pointers.
  926.      * ----------------
  927.      */
  928.     nct = (struct catctup *)
  929.         palloc(sizeof(struct catctup));
  930.     
  931.     nct->ct_tup = ntp;
  932.     
  933.     SLNewNode(&nct->ct_node);
  934.     SLNewNode(&nct->ct_lrunode);
  935.     SLAddHead(&cache->cc_lrulist, &nct->ct_lrunode);
  936.     SLAddHead(&cache->cc_cache[hash], &nct->ct_node);
  937.     
  938.     /* ----------------
  939.      *  deal with hash bucket overflow
  940.      * ----------------
  941.      */
  942.     if (++cache->cc_ntup > cache->cc_maxtup) {
  943.         register CatCTup *ct;
  944.         ct = (CatCTup *) SLGetTail(&cache->cc_lrulist);
  945.         
  946.         if (ct != nct) {
  947.          CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",
  948.                 RelationGetRelationName(relation));
  949.         
  950.         CatCacheRemoveCTup(cache, ct);
  951.         }
  952.     } 
  953.     
  954.     CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples",
  955.             RelationGetRelationName(relation),
  956.             cache->cc_ntup, cache->cc_maxtup);
  957.     CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d",
  958.             RelationGetRelationName(relation), hash);
  959.     }
  960.     
  961.     /* ----------------
  962.      *    close the relation, switch back to the original memory context
  963.      *  and return the tuple we found (or NULL)
  964.      * ----------------
  965.      */
  966.     heap_close(relation);
  967.    
  968.     MemoryContextSwitchTo(oldcxt);
  969.     return ntp;
  970. }
  971.  
  972. /* --------------------------------
  973.  *  RelationInvalidateCatalogCacheTuple()
  974.  *
  975.  *  Invalidate a tuple from a specific relation.  This call determines the
  976.  *  cache in question and calls CatalogCacheIdInvalidate().  It is -ok-
  977.  *  if the relation cannot be found, it simply means this backend has yet
  978.  *  to open it.
  979.  * --------------------------------
  980.  */
  981.  
  982. /**** xxref:
  983.  *           RelationInvalidateHeapTuple
  984.  ****/
  985. void
  986. RelationInvalidateCatalogCacheTuple(relation, tuple, function)
  987.     Relation    relation;
  988.     HeapTuple    tuple;
  989.     void    (*function)();
  990. {
  991.     struct catcache     *ccp;
  992.     MemoryContext    oldcxt;
  993.     ObjectId        relationId;
  994.  
  995.     /* ----------------
  996.      *    sanity checks
  997.      * ----------------
  998.      */
  999.     Assert(RelationIsValid(relation));
  1000.     Assert(HeapTupleIsValid(tuple));
  1001.     CACHE1_elog(DEBUG, "RelationInvalidateCatalogCacheTuple: called");
  1002.     
  1003.     /* ----------------
  1004.      *    switch to the cache memory context
  1005.      * ----------------
  1006.      */
  1007.     if (!CacheCxt)
  1008.        CacheCxt = CreateGlobalMemory("Cache");
  1009.     oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
  1010.     
  1011.     /* ----------------
  1012.      *    for each cache
  1013.      *     if the cache contains tuples from the specified relation
  1014.      *           call the invalidation function on the tuples
  1015.      *           in the proper hash bucket
  1016.      * ----------------
  1017.      */
  1018.     relationId = RelationGetRelationId(relation);
  1019.     
  1020.     for (ccp = Caches; ccp; ccp = ccp->cc_next) {
  1021.         if (relationId != ccp->relationId) 
  1022.         continue;
  1023.     
  1024.     /* OPT inline simplification of CatalogCacheIdInvalidate */
  1025.     if (!PointerIsValid(function)) {
  1026.         function = CatalogCacheIdInvalidate;
  1027.     }
  1028.     
  1029.     (*function)(ccp->id,
  1030.             CatalogCacheComputeTupleHashIndex(ccp, relation, tuple),
  1031.             &tuple->t_ctid);
  1032.     
  1033.     heap_close(relation);
  1034.     }
  1035.     
  1036.     /* ----------------
  1037.      *    return to the proper memory context
  1038.      * ----------------
  1039.      */
  1040.     MemoryContextSwitchTo(oldcxt);
  1041.     
  1042.     /*    sendpm('I', "Invalidated tuple"); */
  1043. }
  1044.  
  1045.